﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DeployGames.TweenEngine.equations
{
    public abstract class Elastic : TweenEquation
    {
        private static float PI = 3.14159265f;

        public static ElasticIN IN = new ElasticIN();
        public static ElasticOUT OUT = new ElasticOUT();
        public static ElasticINOUT INOUT = new ElasticINOUT();

        protected float param_a;
        protected float param_p;
        protected bool setA = false;
        protected bool setP = false;

        public Elastic a(float a)
        {
            param_a = a;
            this.setA = true;
            return this;
        }

        public Elastic p(float p)
        {
            param_p = p;
            this.setP = true;
            return this;
        }

        #region ElasticIN
        public class ElasticIN : Elastic
        {

            public override float compute(float t)
            {
                float a = param_a;
                float p = param_p;
                if (t == 0) return 0; if (t == 1) return 1; if (!setP) p = .3f;
                float s;
                if (!setA || a < 1) { a = 1; s = p / 4; }
                else s = p / (2 * PI) * (float)Math.Asin(1 / a);
                return -(a * (float)Math.Pow(2, 10 * (t -= 1)) * (float)Math.Sin((t - s) * (2 * PI) / p));
            }

            public override string ToString()
            {
                return "Elastic.IN";
            }
        }
        #endregion

        #region ElasticOUT
        public class ElasticOUT : Elastic
        {

            public override float compute(float t)
            {
                float a = param_a;
                float p = param_p;
                if (t == 0) return 0; if (t == 1) return 1; if (!setP) p = .3f;
                float s;
                if (!setA || a < 1) { a = 1; s = p / 4; }
                else s = p / (2 * PI) * (float)Math.Asin(1 / a);
                return a * (float)Math.Pow(2, -10 * t) * (float)Math.Sin((t - s) * (2 * PI) / p) + 1;
            }

            public override string ToString()
            {
                return "Elastic.OUT";
            }
        }
        #endregion

        #region ElasticINOUT
        public class ElasticINOUT : Elastic
        {

            public override float compute(float t)
            {
                float a = param_a;
                float p = param_p;
                if (t == 0) return 0; if ((t *= 2) == 2) return 1; if (!setP) p = .3f * 1.5f;
                float s;
                if (!setA || a < 1) { a = 1; s = p / 4; }
                else s = p / (2 * PI) * (float)Math.Asin(1 / a);
                if (t < 1) return -.5f * (a * (float)Math.Pow(2, 10 * (t -= 1)) * (float)Math.Sin((t - s) * (2 * PI) / p));
                return a * (float)Math.Pow(2, -10 * (t -= 1)) * (float)Math.Sin((t - s) * (2 * PI) / p) * .5f + 1;
            }

            public override string ToString()
            {
                return "Elastic.INOUT";
            }
        }
        #endregion
    }
}
